<template>
  <MainContent back :back-func="true" @back="leaveConfirm" title="编辑流程" class="main-content">
    <div id="container">
      <div id="stencil">
        <side-panel
            :graph="graph"
            @node-dropped="handleNodeDropped"/>
      </div>

      <div id="right">
        <top-toolbar
            :graph="graph"
            :canvas-data="canvasData"
            @submitted="handleSubmitted"
            @test="test">
        </top-toolbar>

        <div id="graph-container-wrapper">
          <div id="graph-container" ></div>
        </div>
      </div>

      <mini-map></mini-map>

      <node-drawer-bootstrap
          ref="nodeDrawerBootstrapRef"
          @modify-canvas-data="handleCanvasData">
      </node-drawer-bootstrap>

      <rename-node-dialog v-model:show="isShowRenameDialog" :current-node="currentNode"></rename-node-dialog>
    </div>
  </MainContent>
</template>

<script>
import {Graph} from "@antv/x6";

import CanvasApi from "@/api/canvasApi";
import {CanvasCreateModel, CanvasModel} from "./dataModel/canvasCreate";

import SidePanel from "./components/SidePanel.vue";
import MiniMap from "./components/MiniMap.vue"
import TopToolbar from "./components/TopToolbar.vue";
import NodeDrawerBootstrap from "@/views/workTable/components/nodeDrawer/NodeDrawerBootstrap.vue";

import useFrom from "./compositions/useFrom";
import useIFrameRequest from "./compositions/useIFrameRequest";
import { useSpacePanning } from "./compositions/useSpacePanning";
import { useLeaveConfirm } from "@/views/workTable/compositions/useLeaveConfirm";

import "./nodes/registerNode";
import * as NodeEvent from "./nodes/nodeEvent";

import "./edges/registerEdge";
import * as EdgeEvent from "./edges/edgeEvent";
import validateConnection from "./edges/validateConnection";
import validateEdge from "./edges/validateEdge.js";
import validateMagnet from "./edges/validateMagnet.js";
import createEdge from "./edges/createEdge.js";

import "./tools/registerTool";
import AddCustomEvent from "@/views/workTable/components/AddCustomEvent.vue";
import RenameNodeDialog from "@/views/workTable/components/RenameNodeDialog.vue";


export default {
  name: "WorkTable",
  components: {
    RenameNodeDialog,
    AddCustomEvent,
    MiniMap,
    NodeDrawerBootstrap,
    SidePanel,
    TopToolbar,
  },

  data() {
    return {};
  },

  // 提供全局公共数据
  provide() {
    return {
      worktableContext: this,
      graph: this.graph,
    }
  },

  // Vue2 => Vue3 逐步迁移到setup中
  setup() {
    const route = useRoute()
    const store = useStore()


    const from = useFrom()
    const {iframeRequest, iframeListener} = useIFrameRequest()

    let graphInstance = ref({})
    const initGraph = () => {
      // #region 初始化画布
      const graph = new Graph({
        container: document.getElementById("graph-container"),
        grid: {
          visible: true, // 绘制网格
          type: "mesh",
          size: 20, // 网格大小 px
          color: "rgb(246,246,246)",
        },
        mousewheel: {
          enabled: true,
          zoomAtMousePosition: true,
          modifiers: "ctrl",
          minScale: 0.5,
          maxScale: 3,
        },
        connecting: {
          snap: {
            radius: 20
          },
          router: {
            name: "manhattan",
            args: {
              step: 20, // 画布的网格大小
            }
          },
          connector: "normal",
          anchor: "center",
          // connectionPoint: 'anchor',
          connectionPoint: {
            name: 'anchor',
            args: {
              offset: 5,
            }
          },
          allowBlank: true,
          allowLoop: false,
          createEdge(e) {
            return createEdge(e, graph);
          },
          validateMagnet(e) {
            // console.log("validateMagnet triggered", e);
            return validateMagnet(e, graph);
          },
          validateConnection(e) {
            // console.log("validateConnection triggered", e);
            return validateConnection(e, graph);
          },
          validateEdge(e) {
            // console.log("validateEdge triggered", e);
            return validateEdge(e, graph);
          },
        },
        highlighting: {
          magnetAdsorbed: {
            name: "stroke",
            args: {
              attrs: {
                fill: "#5F95FF",
                stroke: "#5F95FF",
              },
            },
          },
        },
        selecting: {
          enabled: true,
          rubberband: true,
          showNodeSelectionBox: true,
          // className: 'custom-selecting'
        },
        interacting: {
          // edgeMovable: false,
        },
        snapline: true,
        keyboard: true,
        clipboard: true,
        panning: false,
        minimap: {
          enabled: true,
          container: document.getElementById("minimap-container"),
        },
        scroller: {
          enabled: true,
        },
        history: {
          enabled: true,
          ignoreChange: true,
        }
      });
      // #endregion

      // #region 快捷键与事件
      // copy cut paste
      graph.bindKey(["meta+c", "ctrl+c"], () => {
        const cells = graph.getSelectedCells();
        if (cells.length) {
          graph.copy(cells);
        }
        return false;
      });

      graph.bindKey(["meta+x", "ctrl+x"], () => {
        const cells = graph.getSelectedCells();
        if (cells.length) {
          graph.cut(cells);
        }
        return false;
      });

      graph.bindKey(["meta+v", "ctrl+v"], () => {
        if (!graph.isClipboardEmpty()) {
          const cells = graph.paste({offset: 32});
          graph.cleanSelection();
          graph.select(cells);
        }
        return false;
      });

      graph.bindKey(["meta+z", "ctrl+z"], () => {
        if (graph.history.canUndo()) {
          graph.history.undo();
        }
        return false;
      });

      graph.bindKey(["meta+shift+z", "ctrl+shift+z"], () => {
        if (graph.history.canRedo()) {
          graph.history.redo();
        }
        return false;
      });

      graph.bindKey(["meta+a", "ctrl+a"], () => {
        const nodes = graph.getNodes();
        if (nodes) {
          graph.select(nodes);
        }
      });

      graph.bindKey("backspace", () => {
        const cells = graph.getSelectedCells();
        if (cells.length) {
          graph.removeCells(cells);
        }
      });

      graph.on("blank:click", (e) => {
        NodeEvent.portVisibleSwitch.blankClick(e, graph);
        NodeEvent.deleteButtonVisibleSwitch.blankClick(e, graph);
      });

      graph.on("cell:selected", (e) => {
        NodeEvent.portVisibleSwitch.cellselected(e, graph)
        NodeEvent.deleteButtonVisibleSwitch.cellselected(e, graph)
      })

      graph.on("node:dblclick", (e) => {
        handleDblNode(e)
      });

      graph.on("node:mouseenter", (e) => {
        NodeEvent.portVisibleSwitch.mouseenter();
        NodeEvent.deleteButtonVisibleSwitch.mouseenter(e);
      });

      graph.on("node:mouseleave", (e) => {
        NodeEvent.portVisibleSwitch.mouseleave();
        NodeEvent.deleteButtonVisibleSwitch.mouseleave(e);
      });

      graph.on("node:mousedown", (e) => {
        EdgeEvent.SupportSegmentTool.nodemousedown(e, graph);
        NodeEvent.PlaceholderReplace.nodemousedown(e, graph);
      })

      graph.on("node:mouseup", (e) => {
        EdgeEvent.SupportSegmentTool.nodemouseup(e, graph);
        NodeEvent.PlaceholderReplace.nodemouseup(e, graph);
      })

      graph.on("edge:added", (e) => {
        EdgeEvent.CreatePlaceholderNode.edgeadded(e, graph)
      })

      graph.on("edge:mouseenter", (e) => {
        EdgeEvent.DeleteIconVisibleEvent.mouseenter(e);
        EdgeEvent.SegmentsToolVisible.edgemouseenter(e, graph);
      });

      graph.on("edge:mouseleave", (e) => {
        EdgeEvent.DeleteIconVisibleEvent.mouseleave(e);
        EdgeEvent.SegmentsToolVisible.edgemouseleave(e)
        EdgeEvent.CreatePlaceholderNode.edgemouseleave(e, graph);
      });

      graph.on("edge:connected", (e) => {
        EdgeEvent.SupportSegmentTool.edgeconnected(e, graph)
      });

      graph.on("edge:dblclick", (e) => {
        EdgeEvent.DeleteEdge.edgedblclick(e, graph)
      });

      graphInstance.value = graph;
    }

    // 节点操作-双击
    const handleDblNode = (e) => {
      if (from !== 'sass') {
        openNodeDrawer(e.cell)
      } else {
        openRenameNodeDialog(e.cell)
      }
    }

    // 节点操作-拖拽放置
    const handleNodeDropped = (cell) => {
      openNodeDrawer(cell)
    }

    // 填写节点表单
    const nodeDrawerBootstrapRef = ref()
    const openNodeDrawer = (cell) => {
      nodeDrawerBootstrapRef.value?.showDrawer({
        cell,
        graph: graphInstance.value,
        canvasData: canvasData.value
      }) // TODO 通过props传递数据更佳，但是props数据更新总是滞后，待修复
    }

    // 开始节点的数据直接修改
    const handleCanvasData = (canvasDataProps) => {
      // this.canvasData = {...this.canvasData, ...canvasDataProps};
      canvasData.value = {
        ...canvasData.value,
        ...canvasDataProps,
      }
    }

    // 重命名节点
    const isShowRenameDialog = ref(false)
    const currentNode = ref()
    const openRenameNodeDialog = (cell) => {
      isShowRenameDialog.value = true
      currentNode.value = cell
    }

    // 获取画布数据 - 常规流程数据
    const getCanvasData = async () => {
      const {id} = route.query;

      const rs = await CanvasApi.canvasGetInfo({id});
      handleGetCanvasDataSuccess(rs)
    }

    // 获取画布数据 - 根据模板ID获取模板流程画布信息
    const getTemplateCanvasData = async () => {
      const {merchantTemplateId} = this.$route.query;
      const rs = await CanvasApi.canvasGetTemplateInfo({id: merchantTemplateId});
      handleGetCanvasDataSuccess(rs)
    }

    // 画布数据格式化 转换成画布能用的数据格式
    let canvasData = ref({ // 因为有需要直接修改整个对象的情况，这里直接使用ref而不是reactive
      ...new CanvasModel().getStructure(),
    })
    let eventsData = ref([])
    const handleGetCanvasDataSuccess = (rs) => {
      if (rs && rs.code !== 200) {
        ElMessage.error("加载画布信息失败");
        return;
      }
      const {canvas, nodes, edges, events} = new CanvasCreateModel({graph: graphInstance}).transferDataToPage(rs.payload);

      store.commit('event/setPushEventTemp', events)
      canvasData.value = canvas;
      eventsData.value = events;
      graphInstance.value.fromJSON({
        edges: edges,
        cells: nodes,
      });
      graphInstance.value.centerContent();
    }

    // 画布之外的事件处理
    const {bindSpaceKey, unbindSpaceKey} = useSpacePanning(graphInstance)

    // 退出确认
    const disableLeaveConfirm = ref(false)
    const { leaveConfirm } = useLeaveConfirm(disableLeaveConfirm)
    const handleSubmitted = () => {
      disableLeaveConfirm.value = true
    }

    onMounted(async () => {
      initGraph()

      store.commit("event/reset")

      // 常规流程
      if (route.query.id) {
        await getCanvasData();
      }

      // 商户模板
      if (route.query.merchantTemplateId) {
        await getTemplateCanvasData()
      }

      bindSpaceKey(graphInstance.value)
    })

    onBeforeUnmount(() => {
      graphInstance.value.dispose()
      unbindSpaceKey(graphInstance.value)
    })

    return {
      // 画布实例
      graph: graphInstance,

      // 画布节点对话框
      handleNodeDropped,
      openNodeDrawer,
      nodeDrawerBootstrapRef,
      isShowRenameDialog,
      currentNode,

      // 画布数据
      handleGetCanvasDataSuccess,
      canvasData,
      eventsData,

      // 画布数据的修改
      handleCanvasData,

      // 模板iframe 相关
      from,
      iframeRequest,
      iframeListener,

      // 退出
      leaveConfirm,
      handleSubmitted,
    }
  },

  async mounted() {
    this.graph.workTable = this; // TODO THIS 指向 验证

    this.bindResizeEvent();

    this.iframeListener(this)
  },

  beforeUnmount() {
    this.unbindResizeEvent()
  },

  methods: {
    // 绑定窗口大小变更事件
    bindResizeEvent() {
      this.thatResize = this.resize.bind(this);
      window.addEventListener("resize", this.thatResize);
    },

    // 窗口大小变更事件
    resize() {
      clearTimeout(this.resizeDelayTimer);
      this.resizeDelayTimer = setTimeout(() => {
        const containerWrapperRect = document
            .querySelector("#graph-container-wrapper")
            .getBoundingClientRect();
        this.graph.resize(
            containerWrapperRect.width,
            containerWrapperRect.height
        );
      }, 1000);
    },

    // 解绑窗口大小变更事件
    unbindResizeEvent() {
      window.removeEventListener("resize", this.thatResize);
      clearTimeout(this.resizeDelayTimer);
    },

    test() {
      console.log('top toolbar test button clicked.')
    },

    /**
     * sass平台嵌套此页面到iframe中时会调用。
     * 新建模板时混入页面数据
     * @param canvasData 开始节点中的数据
     */
    iframe_mixCanvasData(canvasData) {
      this.canvasData = {
        ...this.canvasData,
        ...canvasData
      }

      console.log('iframe_mixinCanvasData ===>', this.canvasData)
    },

    /**
     * merchant模板iframe，sass平台模板iframe中 会调用。
     * 根据ID 从sass平台获取 画布信息
     * @param canvasData 画布信息 含画布数据 节点数据 边连接关系数据 公共事件列表
     */
    iframe_getCanvasData(canvasData) { // TODO 理论可以使用this调用到方法，待验证
      this.handleGetCanvasDataSuccess(canvasData)
    },
  },
};
</script>

<style scoped lang="scss">
$stencilWidth: 360px;

.main-content {
  :deep(.all-content) {
    height: calc(100vh - 100px);
  }

  :deep(.content-slot) {
    height: 100%;
  }

  :deep(.white) {
    padding: 0 !important;
  }
}

#container {
  background: rgba(244, 246, 249, 1);
  position: relative;
  height: 100%;
  //height: 600px;
  min-width: 700px;
}

#stencil {
  width: $stencilWidth;
  height: 100%;
  position: absolute;
  top: 0;
  left: 0;
}

#right {
  height: 100%;
  position: relative;
  margin-left: $stencilWidth + 10px;

  display: flex;
  flex-direction: column;
  background: white;

  //#work-table-top-toolbar {
  //  padding: 0 25px;
  //  height: 80px;
  //  display: flex;
  //  align-items: center;
  //  box-shadow: 0 5px 6px -1px rgba(0, 0, 0, 0.06);
  //
  //  :deep(.el-input) {
  //    margin-right: 16px;
  //
  //    .el-input__inner {
  //      border: unset;
  //    }
  //  }
  //}

  #graph-container-wrapper {
    width: 100%;
    height: 100%;

    #graph-container {
      width: 100%;
      height: 100%;
    }
  }
}

</style>
